import 'package:flutter/foundation.dart';

enum AssetType {
  nft,
  stablecoin,
  derivative,
  other,
}

enum RiskLevel {
  low,
  moderate,
  high,
  extreme,
}

class UserAsset {
  final String id;
  final String userId;
  final AssetType assetType;
  final String assetId;
  final String assetName;
  final String? assetSymbol;
  final double quantity;
  final double currentPrice;
  final double currentValue;
  final DateTime acquisitionDate;
  final double acquisitionPrice;
  final String? assetImageUrl;
  final Map<String, dynamic>? metadata;

  const UserAsset({
    required this.id,
    required this.userId,
    required this.assetType,
    required this.assetId,
    required this.assetName,
    this.assetSymbol,
    required this.quantity,
    required this.currentPrice,
    required this.currentValue,
    required this.acquisitionDate,
    required this.acquisitionPrice,
    this.assetImageUrl,
    this.metadata,
  });

  double get totalAcquisitionCost => quantity * acquisitionPrice;
  double get profitLoss => currentValue - totalAcquisitionCost;
  double get profitLossPercentage => totalAcquisitionCost > 0 ? (profitLoss / totalAcquisitionCost) * 100 : 0;
  double get holdingPeriod => DateTime.now().difference(acquisitionDate).inDays.toDouble();

  factory UserAsset.fromJson(Map<String, dynamic> json) {
    return UserAsset(
      id: json['id'] as String,
      userId: json['userId'] as String,
      assetType: AssetType.values.firstWhere(
        (e) => e.toString().split('.').last == json['assetType'],
      ),
      assetId: json['assetId'] as String,
      assetName: json['assetName'] as String,
      assetSymbol: json['assetSymbol'] as String?,
      quantity: (json['quantity'] as num).toDouble(),
      currentPrice: (json['currentPrice'] as num).toDouble(),
      currentValue: (json['currentValue'] as num).toDouble(),
      acquisitionDate: DateTime.parse(json['acquisitionDate'] as String),
      acquisitionPrice: (json['acquisitionPrice'] as num).toDouble(),
      assetImageUrl: json['assetImageUrl'] as String?,
      metadata: json['metadata'] as Map<String, dynamic>?,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'userId': userId,
      'assetType': assetType.toString().split('.').last,
      'assetId': assetId,
      'assetName': assetName,
      'assetSymbol': assetSymbol,
      'quantity': quantity,
      'currentPrice': currentPrice,
      'currentValue': currentValue,
      'acquisitionDate': acquisitionDate.toIso8601String(),
      'acquisitionPrice': acquisitionPrice,
      'assetImageUrl': assetImageUrl,
      'metadata': metadata,
    };
  }

  UserAsset copyWith({
    String? id,
    String? userId,
    AssetType? assetType,
    String? assetId,
    String? assetName,
    String? assetSymbol,
    double? quantity,
    double? currentPrice,
    double? currentValue,
    DateTime? acquisitionDate,
    double? acquisitionPrice,
    String? assetImageUrl,
    Map<String, dynamic>? metadata,
  }) {
    return UserAsset(
      id: id ?? this.id,
      userId: userId ?? this.userId,
      assetType: assetType ?? this.assetType,
      assetId: assetId ?? this.assetId,
      assetName: assetName ?? this.assetName,
      assetSymbol: assetSymbol ?? this.assetSymbol,
      quantity: quantity ?? this.quantity,
      currentPrice: currentPrice ?? this.currentPrice,
      currentValue: currentValue ?? this.currentValue,
      acquisitionDate: acquisitionDate ?? this.acquisitionDate,
      acquisitionPrice: acquisitionPrice ?? this.acquisitionPrice,
      assetImageUrl: assetImageUrl ?? this.assetImageUrl,
      metadata: metadata ?? this.metadata,
    );
  }
}

class AssetOverview {
  final double totalValue;
  final int totalAssets;
  final Map<AssetType, AssetSummary> assetBreakdown;
  final DateTime lastUpdated;

  const AssetOverview({
    required this.totalValue,
    required this.totalAssets,
    required this.assetBreakdown,
    required this.lastUpdated,
  });

  factory AssetOverview.fromJson(Map<String, dynamic> json) {
    final breakdown = <AssetType, AssetSummary>{};
    (json['assetBreakdown'] as Map<String, dynamic>).forEach((key, value) {
      final assetType = AssetType.values.firstWhere(
        (e) => e.toString().split('.').last == key,
      );
      breakdown[assetType] = AssetSummary.fromJson(value as Map<String, dynamic>);
    });

    return AssetOverview(
      totalValue: (json['totalValue'] as num).toDouble(),
      totalAssets: json['totalAssets'] as int,
      assetBreakdown: breakdown,
      lastUpdated: DateTime.parse(json['lastUpdated'] as String),
    );
  }

  Map<String, dynamic> toJson() {
    final breakdown = <String, dynamic>{};
    assetBreakdown.forEach((key, value) {
      breakdown[key.toString().split('.').last] = value.toJson();
    });

    return {
      'totalValue': totalValue,
      'totalAssets': totalAssets,
      'assetBreakdown': breakdown,
      'lastUpdated': lastUpdated.toIso8601String(),
    };
  }
}

class AssetSummary {
  final int count;
  final double value;
  final double percentage;

  const AssetSummary({
    required this.count,
    required this.value,
    required this.percentage,
  });

  factory AssetSummary.fromJson(Map<String, dynamic> json) {
    return AssetSummary(
      count: json['count'] as int,
      value: (json['value'] as num).toDouble(),
      percentage: (json['percentage'] as num).toDouble(),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'count': count,
      'value': value,
      'percentage': percentage,
    };
  }
}

class InvestmentAnalysis {
  final double totalReturn;
  final double annualizedReturn;
  final double volatility;
  final RiskLevel riskLevel;
  final double sharpeRatio;
  final double maxDrawdown;
  final Map<String, double> assetCorrelation;
  final List<Recommendation> recommendations;
  final List<PerformanceData> historicalPerformance;

  const InvestmentAnalysis({
    required this.totalReturn,
    required this.annualizedReturn,
    required this.volatility,
    required this.riskLevel,
    required this.sharpeRatio,
    required this.maxDrawdown,
    required this.assetCorrelation,
    required this.recommendations,
    required this.historicalPerformance,
  });

  factory InvestmentAnalysis.fromJson(Map<String, dynamic> json) {
    return InvestmentAnalysis(
      totalReturn: (json['totalReturn'] as num).toDouble(),
      annualizedReturn: (json['annualizedReturn'] as num).toDouble(),
      volatility: (json['volatility'] as num).toDouble(),
      riskLevel: RiskLevel.values.firstWhere(
        (e) => e.toString().split('.').last == json['riskLevel'],
      ),
      sharpeRatio: (json['sharpeRatio'] as num).toDouble(),
      maxDrawdown: (json['maxDrawdown'] as num).toDouble(),
      assetCorrelation: Map<String, double>.from(
        (json['assetCorrelation'] as Map<String, dynamic>).map(
          (k, v) => MapEntry(k, (v as num).toDouble()),
        ),
      ),
      recommendations: (json['recommendations'] as List)
          .map((e) => Recommendation.fromJson(e as Map<String, dynamic>))
          .toList(),
      historicalPerformance: (json['historicalPerformance'] as List)
          .map((e) => PerformanceData.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'totalReturn': totalReturn,
      'annualizedReturn': annualizedReturn,
      'volatility': volatility,
      'riskLevel': riskLevel.toString().split('.').last,
      'sharpeRatio': sharpeRatio,
      'maxDrawdown': maxDrawdown,
      'assetCorrelation': assetCorrelation,
      'recommendations': recommendations.map((e) => e.toJson()).toList(),
      'historicalPerformance': historicalPerformance.map((e) => e.toJson()).toList(),
    };
  }
}

class Recommendation {
  final String id;
  final String title;
  final String description;
  final RecommendationType type;
  final double confidenceScore;
  final Map<String, dynamic> metadata;

  const Recommendation({
    required this.id,
    required this.title,
    required this.description,
    required this.type,
    required this.confidenceScore,
    required this.metadata,
  });

  factory Recommendation.fromJson(Map<String, dynamic> json) {
    return Recommendation(
      id: json['id'] as String,
      title: json['title'] as String,
      description: json['description'] as String,
      type: RecommendationType.values.firstWhere(
        (e) => e.toString().split('.').last == json['type'],
      ),
      confidenceScore: (json['confidenceScore'] as num).toDouble(),
      metadata: json['metadata'] as Map<String, dynamic>,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'title': title,
      'description': description,
      'type': type.toString().split('.').last,
      'confidenceScore': confidenceScore,
      'metadata': metadata,
    };
  }
}

enum RecommendationType {
  asset,
  strategy,
  education,
  market_insight,
}

class PerformanceData {
  final DateTime date;
  final double value;
  final double? benchmark;

  const PerformanceData({
    required this.date,
    required this.value,
    this.benchmark,
  });

  factory PerformanceData.fromJson(Map<String, dynamic> json) {
    return PerformanceData(
      date: DateTime.parse(json['date'] as String),
      value: (json['value'] as num).toDouble(),
      benchmark: json['benchmark'] != null ? (json['benchmark'] as num).toDouble() : null,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'date': date.toIso8601String(),
      'value': value,
      'benchmark': benchmark,
    };
  }
}

class PersonalizedRecommendation {
  final List<RecommendedAsset> recommendedAssets;
  final List<ContentItem> educationalContent;
  final List<MarketInsight> marketInsights;

  const PersonalizedRecommendation({
    required this.recommendedAssets,
    required this.educationalContent,
    required this.marketInsights,
  });

  factory PersonalizedRecommendation.fromJson(Map<String, dynamic> json) {
    return PersonalizedRecommendation(
      recommendedAssets: (json['recommendedAssets'] as List)
          .map((e) => RecommendedAsset.fromJson(e as Map<String, dynamic>))
          .toList(),
      educationalContent: (json['educationalContent'] as List)
          .map((e) => ContentItem.fromJson(e as Map<String, dynamic>))
          .toList(),
      marketInsights: (json['marketInsights'] as List)
          .map((e) => MarketInsight.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }
}

class RecommendedAsset {
  final String id;
  final String name;
  final String description;
  final AssetType type;
  final double expectedReturn;
  final RiskLevel riskLevel;
  final double confidenceScore;
  final String? imageUrl;

  const RecommendedAsset({
    required this.id,
    required this.name,
    required this.description,
    required this.type,
    required this.expectedReturn,
    required this.riskLevel,
    required this.confidenceScore,
    this.imageUrl,
  });

  factory RecommendedAsset.fromJson(Map<String, dynamic> json) {
    return RecommendedAsset(
      id: json['id'] as String,
      name: json['name'] as String,
      description: json['description'] as String,
      type: AssetType.values.firstWhere(
        (e) => e.toString().split('.').last == json['type'],
      ),
      expectedReturn: (json['expectedReturn'] as num).toDouble(),
      riskLevel: RiskLevel.values.firstWhere(
        (e) => e.toString().split('.').last == json['riskLevel'],
      ),
      confidenceScore: (json['confidenceScore'] as num).toDouble(),
      imageUrl: json['imageUrl'] as String?,
    );
  }
}

class ContentItem {
  final String id;
  final String title;
  final String content;
  final String type;
  final String difficulty;
  final int estimatedReadTime;
  final String? thumbnailUrl;

  const ContentItem({
    required this.id,
    required this.title,
    required this.content,
    required this.type,
    required this.difficulty,
    required this.estimatedReadTime,
    this.thumbnailUrl,
  });

  factory ContentItem.fromJson(Map<String, dynamic> json) {
    return ContentItem(
      id: json['id'] as String,
      title: json['title'] as String,
      content: json['content'] as String,
      type: json['type'] as String,
      difficulty: json['difficulty'] as String,
      estimatedReadTime: json['estimatedReadTime'] as int,
      thumbnailUrl: json['thumbnailUrl'] as String?,
    );
  }
}

class MarketInsight {
  final String id;
  final String title;
  final String summary;
  final String category;
  final DateTime publishedDate;
  final double relevanceScore;

  const MarketInsight({
    required this.id,
    required this.title,
    required this.summary,
    required this.category,
    required this.publishedDate,
    required this.relevanceScore,
  });

  factory MarketInsight.fromJson(Map<String, dynamic> json) {
    return MarketInsight(
      id: json['id'] as String,
      title: json['title'] as String,
      summary: json['summary'] as String,
      category: json['category'] as String,
      publishedDate: DateTime.parse(json['publishedDate'] as String),
      relevanceScore: (json['relevanceScore'] as num).toDouble(),
    );
  }
}